from flask import Flask, jsonify, g
from flask_cors import CORS
from flask_migrate import Migrate
from src.config.config import config
from src.database import db, init_db, close_db
from src.models.db import init_db_pool, get_db, close_all_connections
import sys
import os
import traceback

# 创建扩展实例
migrate = Migrate()

def create_app(config_name='default'):
    """应用工厂函数"""
    app = Flask(__name__)

    # 加载配置
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)

    # 初始化扩展
    CORS(app, resources={r"/api/*": {"origins": "*"}})
    
    # 初始化SQLAlchemy（必须在migrate之前）
    db.init_app(app)
    migrate.init_app(app, db)
    
    # 初始化数据库连接池（测试环境跳过，使用内存数据库）
    if not app.config.get('TESTING', False):
        try:
            init_db_pool()
            print("数据库连接池初始化成功")
        except Exception as e:
            print(f"数据库连接池初始化失败: {str(e)}")
            print("错误详情:")
            traceback.print_exc()
            sys.exit(1)
        
        # 注册数据库关闭函数（仅非测试环境）
        app.teardown_appcontext(close_db)

    # 注册蓝图
    from src.controllers.auth import auth_bp
    from src.controllers.course import course_bp
    from src.controllers.major import major_bp
    from src.controllers.teacher import teacher_bp
    from src.controllers.major_plan import major_plan_bp

    # 注册认证路由（不需要认证）
    app.register_blueprint(auth_bp, url_prefix='/api/auth')
    
    # 注册业务路由（部分需要认证）
    app.register_blueprint(course_bp, url_prefix='/api/courses')
    app.register_blueprint(major_bp, url_prefix='/api/majors')
    app.register_blueprint(teacher_bp, url_prefix='/api/teachers')
    app.register_blueprint(major_plan_bp, url_prefix='/api/major-plans')

    # 错误处理
    @app.errorhandler(404)
    def not_found(error):
        return jsonify({
            'message': '资源不存在',
            'error': 'not_found'
        }), 404

    @app.errorhandler(500)
    def internal_error(error):
        print("服务器错误:")
        traceback.print_exc()
        return jsonify({
            'message': '服务器内部错误',
            'error': str(error)
        }), 500
        
    @app.errorhandler(Exception)
    def handle_exception(error):
        print("未处理的异常:")
        traceback.print_exc()
        return jsonify({
            'message': '服务器内部错误',
            'error': str(error)
        }), 500

    # 添加测试路由（仅非测试环境）
    if not app.config.get('TESTING', False):
        @app.route('/api/test')
        def test():
            try:
                from src.models.db import get_db
                db = get_db()
                cursor = db.cursor()
                cursor.execute("SELECT 1")
                result = cursor.fetchone()
                cursor.close()
                return jsonify({
                    'status': 'success',
                    'message': '数据库连接测试成功',
                    'data': result[0]
                })
            except Exception as e:
                print("数据库测试失败:")
                traceback.print_exc()
                return jsonify({
                    'status': 'error',
                    'message': f'数据库连接测试失败: {str(e)}'
                }), 500
        
    # 数据库连接处理（仅非测试环境）
    if not app.config.get('TESTING', False):
        @app.before_request
        def before_request():
            g.db = get_db()

        @app.teardown_request
        def teardown_request(exception):
            db = g.pop('db', None)
            if db is not None:
                close_db(db)

        @app.route('/test_db')
        def test_db():
            try:
                conn = get_db()
                cursor = conn.cursor()
                cursor.execute('SELECT 1')
                result = cursor.fetchone()
                close_db(conn)
                return jsonify({'status': 'success', 'message': 'Database connection successful', 'result': result})
            except Exception as e:
                return jsonify({'status': 'error', 'message': str(e)}), 500

    return app

# 不在模块级别创建app实例，使用应用工厂模式
# 测试环境通过 create_app('testing') 创建
# 生产环境通过 create_app() 或 create_app('production') 创建
# 这里不创建app实例，避免在导入时连接数据库

if __name__ == '__main__':
    app = create_app()
    try:
        if not app.config.get('TESTING', False):
            init_db_pool()
        app.run(debug=True)
    finally:
        if not app.config.get('TESTING', False):
            close_all_connections()
